package com.ichir.projects.uiframework.xml;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlIDREF;
import javax.xml.bind.annotation.XmlRootElement;

import com.ichir.projects.uiflow.definition.FlowType;
import com.ichir.projects.uiflow.definition.IFlowDefinition;
import com.ichir.projects.uiflow.definition.IFlowPart;


/**
 * {@link IFlowDefinition} XML implementation of the flow definition.
 * Root XML element.
 * 
 * @author mahieddine_ichir
 */
@XmlRootElement(name="uiflow")
@XmlAccessorType(XmlAccessType.FIELD)
public class XmlFlowDefinition implements IFlowDefinition {

	@XmlAttribute(name="start", required=true)
	@XmlIDREF
	private XmlFlowPart startingUiPart;

	@XmlElement(name="end")
	@XmlIDREF
	private XmlFlowPart end;

	@XmlAttribute(required=true)
	private String id;

	@XmlElement(name="property")
	private List<XmlProperty> properties;
	
	@XmlElement(name="action")
	private List<XmlAction> actions;

	@XmlElement(name="bean")
	private List<XmlBean> beans;
	
	@XmlElement(name="view")
	private List<XmlView> views;

	private Map<FlowType, ArrayList<IFlowPart>> flowParts = new HashMap<FlowType, ArrayList<IFlowPart>>();

	@Override
	public String getId() {
		return id;
	}

	/**
	 * @param id the id to set
	 */
	public void setId(String id) {
		this.id = id;
	}

	@Override
	public List<? extends IFlowPart> getActions() {
		if (flowParts.get(FlowType.ACTION) == null) {
			return actions;
		} else {
			List<IFlowPart> list = new ArrayList<IFlowPart>(actions);
			list.addAll(flowParts.get(FlowType.ACTION));
			return list;
		}
	}

	/**
	 * @param actions the actions to set
	 */
	public void setActions(List<XmlAction> actions) {
		this.actions = actions;
	}


	@Override
	public List<? extends IFlowPart> getViews() {
		if (flowParts.get(FlowType.VIEW) == null) {
			return views;
		} else {
			List<IFlowPart> list = new ArrayList<IFlowPart>(views);
			list.addAll(flowParts.get(FlowType.VIEW));
			return list;
		}
	}

	/**
	 * @param views the views to set
	 */
	public void setViews(List<XmlView> views) {
		this.views = views;
	}

	@Override
	public IFlowPart getEnd() {
		return end;
	}

	/**
	 * @param end the end to set
	 */
	public void setEnd(XmlFlowPart end) {
		this.end = end;
	}

	@Override
	public IFlowPart getStart() {
		return startingUiPart;
	}

	/**
	 * @param start
	 */
	public void setStartingUiPart(XmlFlowPart start) {
		this.startingUiPart = start;
	}

	@Override
	public Map<String, Object> getProperties() {
		if (properties == null) {
			return Collections.emptyMap();
		}
		// immutable map
		Map<String, Object> props = new HashMap<String, Object>();
		for (XmlProperty property : properties) {
			if (property.getBean() != null) {
				props.put(property.getName(), XmlBeanHelper.getBean(property.getBean()));
			} else {
				props.put(property.getName(), property.getValue());
			}
		}
		return props;
	}

	/**
	 * @param properties set flow properties
	 */
	public void setProperties(List<XmlProperty> properties) {
		this.properties = properties;
	}

	/**
	 * @return flow declared beans
	 */
	public List<XmlBean> getBeans() {
		return beans;
	}

	/**
	 * Set flow beans.
	 * @param beans beans to set
	 */
	public void setBeans(List<XmlBean> beans) {
		this.beans = beans;
	}
} 
